#include "bin_crc.h"

static uint32_t midCrcComputeCrc32Ext(uint32_t init_value, uint8_t *buf, uint32_t buf_len);
static uint32_t appComputeCrc32Start64(uint32_t u32StartData, const uint8_t u8Buf[], uint32_t u32DataLength);

/**
  * @brief calculation crc32 value
  *
  * @param[in]  u32StartData: start value .
  * @param[in]  u8Buf: the input data buff  .
  * @param[in]  u32DataLength: the input data length  .
  * @return   u32Crc32Data : crc32value.
  *
  * @details the function is used to calculation crc32 value .
  */
uint32_t appComputeCrc32Start(uint32_t u32StartData, const uint8_t u8Buf[], uint32_t u32DataLength)
{
	/*  5812 */
	uint32_t	u32TempI;
	uint32_t	u32Crc32Data;
	uint8_t		u8DataCounter;

	if (u32DataLength <= 64U)
	{
		u32Crc32Data = appComputeCrc32Start64(u32StartData, u8Buf, u32DataLength);
	}
	else
	{
		u8DataCounter = u32DataLength / 64U;
		for (u32TempI = 0U; u32TempI < u8DataCounter; u32TempI++)
		{
			u32Crc32Data = appComputeCrc32Start64(u32StartData, u8Buf + (64U * u32TempI), 64);
			u32StartData = u32Crc32Data;
			u32DataLength = u32DataLength - 64U;
		}
		if (u32DataLength != 0U)
		{
			u32Crc32Data = appComputeCrc32Start64(u32StartData, u8Buf + (64U * u8DataCounter), u32DataLength);
		}

	}
	return (u32Crc32Data);
}

static uint32_t appComputeCrc32Start64(uint32_t u32StartData, const uint8_t u8Buf[], uint32_t u32DataLength)
{
	/*  5812 */
	uint32_t	u32Crc32Data;
	uint8_t		u8TempBuff[64];

	if (u32DataLength <= 64)
	{
		memcpy(u8TempBuff, u8Buf, u32DataLength);
		u32Crc32Data = midCrcComputeCrc32Ext(u32StartData, u8TempBuff, u32DataLength);
	}
	else
	{
		u32Crc32Data = 0U;
	}
	return (u32Crc32Data);
}

static uint32_t midCrcComputeCrc32Ext(uint32_t u32StartData, uint8_t u8Buf[], uint32_t u32DataLength)
{
	/* 5828 */
	uint32_t	u32TempI;
	uint32_t	u32TempJ;
	uint32_t	u32Crc32Data;
	uint32_t	u32Value;

	u32Crc32Data = u32StartData;
	for (u32TempI = 0; u32TempI < u32DataLength; u32TempI++)
	{
		u32Value = (u32Crc32Data ^ u8Buf[u32TempI]) & 0xff;
		for (u32TempJ = 0; u32TempJ < 8; u32TempJ++ )
		{
			u32Value = ((u32Value & 0x01) != 0) ? (0xedb88320 ^ (u32Value >> 1)) : (u32Value >> 1);
		}
		u32Crc32Data = (( u32Crc32Data >> 8) & 0xFFFFFF) ^ u32Value;
	}
	return (u32Crc32Data);
}

